package com.jinmdz.fmis.api.api.service;

import com.jinmdz.fmis.api.api.model.common.IdVersionData;
import com.jinmdz.fmis.api.api.model.settlement.SettleDailyExpensesAllLoadData;
import com.jinmdz.fmis.api.api.model.settlement.SettleDailyExpensesVerifyData;
import com.jinmdz.fmis.api.base.BaseService;
import com.jinmdz.fmis.api.model.config.dictionary.DictionaryCode;
import com.jinmdz.fmis.api.model.config.dictionary.OperationLogCode;
import com.jinmdz.fmis.api.model.system.UserItem;
import com.jinmdz.fmis.api.wrapper.OperationWrapper;
import com.jinmdz.fmis.common.ext.StringBuilderExt;
import com.jinmdz.fmis.common.util.DataUtil;
import com.jinmdz.fmis.core.base.BaseResult;
import com.jinmdz.fmis.core.exception.ActionException;
import com.jinmdz.fmis.core.util.JacksonUtil;
import com.jinmdz.fmis.dao.dao.ChargeSettleDao;
import com.jinmdz.fmis.dao.dao.ChargeVerifyDao;
import com.jinmdz.fmis.dao.model.settlement.ChargeSettleViewItem;
import com.jinmdz.fmis.dao.model.settlement.ChargeVerifyViewItem;
import com.jinmdz.fmis.dao.model.settlement.SettleDailyExpensesAllData;
import com.jinmdz.fmis.dao.model.settlement.SettleDailyExpensesAllSettleItem;
import com.jinmdz.fmis.mapper.entity.ChargeSettleEntity;
import com.jinmdz.fmis.mapper.entity.ChargeVerifyEntity;
import com.jinmdz.fmis.mapper.mapper.ChargeSettleMapper;
import com.jinmdz.fmis.mapper.mapper.ChargeVerifyMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;

/**
 * SettleDailyExpensesService类
 *
 * @author LiCongLu
 * @date 2020-02-21 11:49
 */
@Service("settleDailyExpensesService")
public class SettleDailyExpensesService extends BaseService {


    @Resource
    private ChargeSettleDao chargeSettleDao;

    @Resource
    private ChargeSettleMapper chargeSettleMapper;

    @Resource
    private FuneralBusinessService funeralBusinessService;

    @Resource
    private ChargeVerifyMapper chargeVerifyMapper;

    @Resource
    private ChargeVerifyDao chargeVerifyDao;

    @Resource
    private OperationLogCode operationLogCode;

    @Resource
    private DictionaryCode dictionaryCode;

    @Resource
    private OperationWrapper operationWrapper;

    /**
     * 根据查询条件加载页面数据信息，此接口为按页面定制接口
     *
     * @param data 请求查询数据
     * @return
     * @author LiCongLu
     * @date 2020-02-21 12:15
     */
    public BaseResult<SettleDailyExpensesAllLoadData> loadSettleDailyExpensesAll(SettleDailyExpensesAllData data) {
        SettleDailyExpensesAllLoadData allLoadData = new SettleDailyExpensesAllLoadData();

        ArrayList<SettleDailyExpensesAllSettleItem> chargeSettleItems = chargeVerifyDao.listSettleDailyExpensesAllSettleByData(data, dictionaryCode.getInvoiceStateZuoFei());

        for (SettleDailyExpensesAllSettleItem chargeItem : chargeSettleItems) {
            chargeItem.setAsVerifyText(DataUtil.valid(chargeItem.getAsVerify()) ? "已审核" : "未审核");
        }
        allLoadData.setChargeSettles(chargeSettleItems);

        //设置已审核状态
        ArrayList<ChargeVerifyViewItem> chargeVerifyItems = chargeVerifyDao.listSettleDailyExpensesAllVerifyByData(data);

        allLoadData.setChargeVerifies(chargeVerifyItems);

        // 返回响应结果
        return successData(allLoadData);
    }

    /**
     * 创建日结单，费用日结审核
     *
     * @param data 日结审核数据
     * @return
     * @author LiCongLu
     * @date 2020-02-21 12:18
     */
    @Transactional(rollbackFor = Exception.class)
    public BaseResult saveSettleDailyExpensesVerify(UserItem userItem, SettleDailyExpensesVerifyData data) throws ActionException {
        // 判断是否存在主键
        if (DataUtil.invalid(data.getIds())) {
            throw exception("不存在结算主键");
        }

        // 结算主键处理
        ArrayList<IdVersionData> idList = data.getIds();
        // 验证主键是否重复
        if (idList.size() != getRepeatIdSize(idList)) {
            throw exception("结算主键存在重复");
        }

        // 验证结算发票个数
        if (idList.size() < data.getInvoiceCount().intValue()) {
            throw exception("发票个数大于要结算的个数");
        }

        // 验证结算收据个数
        if (idList.size() < data.getReceiptCount().intValue()) {
            throw exception("收据个数大于要结算的个数");
        }

        // 当前时间
        Date nowDate = nowDate();

        // 记录总金额
        BigDecimal totalCharge = new BigDecimal(0);

        // 记录结算信息
        ArrayList<ChargeSettleViewItem> settleItems = new ArrayList<>();

        // 开始遍历结算验证
        for (IdVersionData idData : data.getIds()) {
            ChargeSettleViewItem settleItem = chargeSettleDao.getChargeSettleViewById(idData.getId());
            if (DataUtil.isNull(settleItem) || DataUtil.isNull(settleItem.getId(), settleItem.getVersion())) {
                throw exception("存在错误结算主键");
            }

            // 验证数据版本号
            if (!DataUtil.equals(settleItem.getVersion(), idData.getVersion())) {
                throw exception(versionError("结算主键"));
            }

            // 验证是否已日结审核
            if (DataUtil.valid(settleItem.getAsVerify())) {
                throw exception("存在已日结审核的结算");
            }

            // 累计结算金额
            totalCharge = totalCharge.add(settleItem.getSettleCharge());
            // 记录结算信息
            settleItems.add(settleItem);
        }

        // 验证日结金额
        if (totalCharge.compareTo(data.getDailyCharge()) != 0) {
            throw exception("要日结审核金额与结算金额不相同");
        }

        // 保存日结审核
        ChargeVerifyEntity verifyEntity = getEntity(userItem, ChargeVerifyEntity.class);
        verifyEntity.setVerifyBatchNo(funeralBusinessService.getVerifyBatchNoAsNew())
                .setVerifyCharge(totalCharge)
                .setVerifyTime(nowDate)
                .setInvoiceCount(data.getInvoiceCount())
                .setReceiptCount(data.getReceiptCount())
                .setVerifyUserId(userItem.getId());

        // 添加日结审核
        chargeVerifyMapper.insertChargeVerify(verifyEntity);

        // 判断日结审核结果
        if (DataUtil.invalid(verifyEntity.getId())) {
            throw exception("保存日结审核失败");
        }

        // 更新结算表日结审核标记
        for (IdVersionData idData : data.getIds()) {
            // 获取结算数据
            ChargeSettleEntity settleEntity = chargeSettleMapper.getChargeSettleById(idData.getId());
            if (DataUtil.isNull(settleEntity) || DataUtil.isNull(settleEntity.getId(), settleEntity.getVersion())) {
                throw exception("存在错误结算主键");
            }
            // 验证数据版本号
            if (!DataUtil.equals(settleEntity.getVersion(), idData.getVersion())) {
                throw exception(versionError("结算主键"));
            }

            // 记录日结审核
            settleEntity.setAsVerify(1)
                    .setVerifyId(verifyEntity.getId())
                    .setModifiedUserId(userItem.getId());
            // 更新结算信息
            chargeSettleMapper.updateChargeSettle(settleEntity);
        }

        // 添加日结审核操作记录
        saveSettleDailyExpensesVerifyLog(userItem, data, verifyEntity, settleItems);

        return success("日结审核完成");
    }

    /**
     * 添加日结审核操作日志记录
     *
     * @param userItem     当前账号
     * @param data         请求数据
     * @param verifyEntity 日结审核数据
     * @param settleItems  结算列表
     * @return
     * @author LiCongLu
     * @date 2020-04-21 09:08
     */
    private void saveSettleDailyExpensesVerifyLog(UserItem userItem, SettleDailyExpensesVerifyData data, ChargeVerifyEntity verifyEntity, ArrayList<ChargeSettleViewItem> settleItems) throws ActionException {
        // 操作日志字符串
        StringBuilderExt builder = new StringBuilderExt();
        builder.format("日结审核信息，日结审核批次编号[{0}]，日结审核金额[{1}]，审核发票个数[{2}]，审核收据个数[{3}]，备注信息[{4}]，操作人员[{5}]"
                , verifyEntity.getVerifyBatchNo(), DataUtil.getPlainString(verifyEntity.getVerifyCharge())
                , String.valueOf(verifyEntity.getInvoiceCount()), String.valueOf(verifyEntity.getReceiptCount())
                , verifyEntity.getRemark(), userItem.getFullName());

        // 添加日志
        operationWrapper.operationLog(userItem, operationLogCode.getChargeVerify(), builder.toString(), JacksonUtil.obj2Json(data), JacksonUtil.obj2Json(settleItems), JacksonUtil.obj2Json(verifyEntity));
    }

    /**
     * 取消日结审核
     *
     * @param data 主键和版本号
     * @return
     * @author LiCongLu
     * @date 2020-02-21 12:33
     */
    @Transactional(rollbackFor = Exception.class)
    public BaseResult saveSettleDailyExpensesCancellationVerify(UserItem userItem, ArrayList<IdVersionData> data) throws ActionException {
        // 判断是否存在主键
        if (DataUtil.invalid(data)) {
            throw exception("不存在日结审核主键");
        }

        // 验证主键是否重复
        if (data.size() != getRepeatIdSize(data)) {
            throw exception("日结审核主键存在重复");
        }

        // 记录日结信息
        ArrayList<ChargeVerifyViewItem> verifyItems = new ArrayList<>();

        // 开始遍历日结审核
        for (IdVersionData idData : data) {
            ChargeVerifyViewItem verifyItem = chargeVerifyDao.getChargeVerifyViewById(idData.getId());
            if (DataUtil.isNull(verifyItem) || DataUtil.isNull(verifyItem.getId(), verifyItem.getVersion())) {
                throw exception("存在错误日结审核主键");
            }

            // 验证数据版本号
            if (!DataUtil.equals(verifyItem.getVersion(), idData.getVersion())) {
                throw exception(versionError("日结审核主键"));
            }

            // 删除日结审核审核标记
            chargeSettleDao.deletedForCancellationVerify(verifyItem.getId(), userItem.getId());

            // 删除日结审核信息
            chargeVerifyMapper.deletedForChargeVerify(verifyItem.getId(), userItem.getId(), verifyItem.getVersion());

            // 记录日结信息
            verifyItems.add(verifyItem);
        }

        // 添加取消日结审核记录信息
        saveSettleDailyExpensesCancellationVerifyLog(userItem, data, verifyItems);

        // 取消日结审核完成
        return success("取消日结审核完成");
    }

    /**
     * 添加取消日结审核操作作日志记录
     *
     * @param userItem    当前账号
     * @param data        请求数据
     * @param verifyItems 日结审核数据
     * @return
     * @author LiCongLu
     * @date 2020-04-21 09:08
     */
    private void saveSettleDailyExpensesCancellationVerifyLog(UserItem userItem, ArrayList<IdVersionData> data, ArrayList<ChargeVerifyViewItem> verifyItems) throws ActionException {
        // 操作日志字符串
        StringBuilderExt builder = new StringBuilderExt();
        builder.format("取消日结审核信息，操作人员[{0}]", userItem.getFullName());

        // 添加日志
        operationWrapper.operationLog(userItem, operationLogCode.getChargeVerify(), builder.toString(), JacksonUtil.obj2Json(data), JacksonUtil.obj2Json(verifyItems), null);
    }
}
